#include <ncurses.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#include "tinyfont.h"

unsigned int t=0; //1320
int time=0; //6
int end=8;
unsigned int pos=0;

int pii[255] = {
  1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,8,4,6,2,6,4,3,3,8,3,2,7,9,5,0,2,8,8,4,1,9,7,1,6,9,3,9,9,3,7,5,1,0,
  5,8,2,0,9,7,4,9,4,4,5,9,2,3,0,7,8,1,6,4,0,6,2,8,6,2,0,8,9,9,8,6,2,8,0,3,4,8,2,5,3,4,2,1,1,7,0,6,7,9,
  8,2,1,4,8,0,8,6,5,1,3,2,8,2,3,0,6,6,4,7,0,9,3,8,4,4,6,0,9,5,5,0,5,8,2,2,3,1,7,2,5,3,5,9,4,0,8,1,2,8,
  4,8,1,1,1,7,4,5,0,2,8,4,1,0,2,7,0,1,9,3,8,5,2,1,1,0,5,5,5,9,6,4,4,6,2,2,9,4,8,9,5,4,9,3,0,3,8,1,9,6,
  4,4,2,8,8,1,0,9,7,5,6,6,5,9,3,3,4,4,6,1,2,8,4,7,5,6,4,8,2,3,3,7,8,6,7,8,3,1,6,5,2,7,1,2,0,1,9,0,9,1,
  4,5,6,4,8};

void printchar(char ch, int ypos, int xpos) {
  int x, y;

  for (y=0;y<8;y++) for (x=0;x<4;x++) {
    if (gluetinyfont[(int)ch]<<(y*4+x) & 0x80000000)
      mvaddch(ypos+y, xpos+x, pii[pos++&255]+'0');
  }
}

void printinvertchar(char ch, int ypos, int xpos) {
  int x, y;

  for (y=0;y<8;y++) for (x=0;x<4;x++) {
    if (gluetinyfont[(int)ch]<<(y*4+x) & 0x80000000)
      mvaddch(ypos+y, xpos+x, 32);
  }
}

void printstr(char *str, int ypos, int xpos) {
  int offset=0;

  while (*str != '\0') {
    printchar(*str, ypos, xpos+offset);
    offset += 5;
    str++;
  }
}

void printinvertstr(char *str, int ypos, int xpos) {
  int offset=0;

  while (*str != '\0') {
    printinvertchar(*str, ypos, xpos+offset);
    offset += 5;
    str++;
  }
}

#define LOGOX 38
#define LOGOY 17

#define NAALIX 64
#define NAALIY 30

#define BIINIX 73
#define BIINIY 30

#define T101X 44
#define T101Y 20

#define DUNCANX 41
#define DUNCANY 23

char pilogo[LOGOX*LOGOY];

char naalikuva[NAALIX*NAALIY];
char biinikuva[BIINIX*BIINIY];
char t101kuva[T101X*T101Y];
char duncankuva[DUNCANX*DUNCANY];

int precalc() {
  int i, x=0, y=0;
  char ch;

  for (i=0;i<LOGOX*LOGOY;i++)
    pilogo[i] = 0;

  FILE *logofile;
  logofile = fopen("pilogo", "r");
  if (!logofile) return 1;

  while ((ch = getc(logofile))!=EOF) {
    if (ch == '\n') {x=0;y++;}
    pilogo[y*LOGOX+x] = ch;
    x++;
  }

  fclose(logofile);

  x=0;y=0;
  logofile = fopen("naali", "r");
  if (!logofile) return 1;

  while ((ch = getc(logofile))!=EOF) {
    if (ch == '\n') {x=0;y++;}
    naalikuva[y*NAALIX+x] = ch;
    x++;
  }
  fclose(logofile);

  x=0;y=0;
  logofile = fopen("biini", "r");
  if (!logofile) return 1;

  while ((ch = getc(logofile))!=EOF) {
    if (ch == '\n') {x=0;y++;}
    biinikuva[y*BIINIX+x] = ch;
    x++;
  }
  fclose(logofile);

  x=0;y=0;
  logofile = fopen("t101", "r");
  if (!logofile) return 1;

  while ((ch = getc(logofile))!=EOF) {
    if (ch == '\n') {x=0;y++;}
    t101kuva[y*T101X+x] = ch;
    x++;
  }
  fclose(logofile);

  x=0;y=0;
  logofile = fopen("duncan", "r");
  if (!logofile) return 1;

  while ((ch = getc(logofile))!=EOF) {
    if (ch == '\n') {x=0;y++;}
    duncankuva[y*DUNCANX+x] = ch;
    x++;
  }
  fclose(logofile);

  return 0;
}

void intro(int rows, int cols) {
  int i;
  static int ypos=4;//, xpos=0;
  static int paska=0, other=0;

  clear();
  attron(A_BOLD);
  if (paska%10==0) other++;
  if (other%2==0)
    printstr("wAMMA", ypos, (cols-5*5)/2);
  else
	printstr("PRIMITIVE", ypos, (cols-9*5)/2);
  attroff(A_BOLD);

  paska++;

  mvprintw(ypos+7, (cols-strlen("P R E S E N T S"))/2, "%s", "P R E S E N T S");

  int mesgpos=0;
  char mesg[]="A text mode demo^D^D^D^Dpieceofshit for 135 Party!";
  for (i=0;i<strlen(mesg);i++) {
    if (i>=(t/2)) break;
    mvaddch(ypos+9, (cols-strlen(mesg))/2+mesgpos, mesg[i]);
    mesgpos++;
  }

  if (t/2>strlen(mesg)+3)
    mvprintw(ypos+11, (cols-strlen("C A L L E D"))/2, "%s", "C A L L E D");

  attron(A_BOLD);
  if (t/2>strlen(mesg)+5)
    printstr("I", ypos+13, (cols-12*5)/2);
  if (t/2>strlen(mesg)+6)
    printstr("want", ypos+13, (cols-12*5)/2+2*5);
  if (t/2>strlen(mesg)+7)
    printstr("to", ypos+13, (cols-12*5)/2+7*5);
  if (t/2>strlen(mesg)+8)
    printstr("Pi", ypos+13, (cols-12*5)/2+10*5);
  attroff(A_BOLD);

  for (i=0;i<50;i++)
	mvaddch(rand()%rows, rand()%cols, pii[pos++&255]+'0');

  refresh();
  usleep(100000);
}

void naali(int rows, int cols) {
  int x,y;
  static int namexpos=0, nameypos=0;
  static int doneinit=0;
  if (!doneinit) {
    namexpos=cols;
    nameypos=rows;
    doneinit++;
  }

  clear();
  printstr("KAKKA", nameypos--, 6);
  printstr("KAKKA", 2, namexpos-=3);

  attron(A_BOLD);
  if (namexpos<-30&&nameypos<-5)
    printstr("KAKKA", 2, 6);
  attroff(A_BOLD);

  attron(A_BOLD);
  for (y=0;y<NAALIY;y++) for (x=0;x<NAALIX;x++)
    if (naalikuva[y*NAALIX+x]>32) mvaddch(y, x+30, pii[pos++&255]+'0');

  attroff(A_BOLD);

  for (x=0;x<50;x++)
	mvaddch(rand()%rows, rand()%cols, pii[pos++&255]+'0');

  refresh();
  usleep(100000);
}

void biini(int rows, int cols) {
  int x,y;
  static int namexpos=0, nameypos=0;
  static int doneinit=0;
  if (!doneinit) {
    namexpos=cols;
    nameypos=0-6;
    doneinit++;
  }

  clear();
  printstr("Mr Bean", nameypos++, 6);
  printstr("Mr Bean", rows-8, namexpos-=3);

  attron(A_BOLD);
  if (namexpos<-30&&nameypos>rows+8)
    printstr("Mr Bean", rows-8, 6);
  attroff(A_BOLD);

  attron(A_BOLD);
  for (y=0;y<BIINIY;y++) for (x=0;x<BIINIX;x++)
    if (biinikuva[y*BIINIX+x]>32) mvaddch(y, x+30, pii[pos++&255]+'0');

  attroff(A_BOLD);

  for (x=0;x<50;x++)
	mvaddch(rand()%rows, rand()%cols, pii[pos++&255]+'0');

  refresh();
  usleep(100000);
}

void t101(int rows, int cols) {
  int x,y;
  static int namexpos=0, nameypos=0;
  static int doneinit=0;
  if (!doneinit) {
    namexpos=0-20;
    nameypos=rows;
    doneinit++;
  }

  clear();
  printstr("T-101", nameypos--, cols-30);
  printstr("T-101", 2, namexpos+=3);

  attron(A_BOLD);
  if (namexpos>cols+2&&nameypos<-5)
    printstr("T-101", 2, cols-30);
  attroff(A_BOLD);

  attron(A_BOLD);
  for (y=0;y<T101Y;y++) for (x=0;x<T101X;x++)
    if (t101kuva[y*T101X+x]>32) mvaddch(y+10, x, pii[pos++&255]+'0');

  attroff(A_BOLD);

  for (x=0;x<50;x++)
	mvaddch(rand()%rows, rand()%cols, pii[pos++&255]+'0');

  refresh();
  usleep(100000);
}

void duncan(int rows, int cols) {
  int x,y;
  static int namexpos=0, nameypos=0;
  static int doneinit=0;
  if (!doneinit) {
    namexpos=0-30;
    nameypos=0-6;
    doneinit++;
  }

  clear();
  printstr("DUNCAN", nameypos++, cols-35);
  printstr("DUNCAN", rows-8, namexpos+=3);

  attron(A_BOLD);
  if (namexpos>cols+2&&nameypos>-rows+8)
    printstr("DUNCAN", rows-8, cols-35);
  attroff(A_BOLD);

  attron(A_BOLD);
  for (y=0;y<DUNCANY;y++) for (x=0;x<DUNCANX;x++)
    if (duncankuva[y*DUNCANX+x]>32) mvaddch(y+7, x, pii[pos++&255]+'0');

  attroff(A_BOLD);

  for (x=0;x<50;x++)
	mvaddch(rand()%rows, rand()%cols, pii[pos++&255]+'0');

  refresh();
  usleep(100000);
}

void onnee(int rows, int cols, int num) {
	int x, y;
	static int starttime=0;
	static int initdone=0;
	if (!initdone) {
		starttime=t;
		initdone++;
	}

  clear();
  for (y=0;y<rows;y++) for (x=0;x<cols;x++)
    mvaddch(y, x, pii[pos++&255]+'0');

  if (t-starttime < 50) {
	printinvertstr("Code", 2, 6);
    printinvertstr("Segrel", (rows-6)/2, (cols-6*5)/2);
  } else if (t-starttime < 100){
	printinvertstr("Music", 2, 6);
    printinvertstr("T-101", (rows-6)/2, (cols-6*5)/2);	
  } else {
	printinvertstr("We wish", 2, 6);
    printinvertstr("HAPPY BIRTHDAY", (rows-6)/2, (cols-14*5)/2);		
    printinvertstr("to", (rows-6)/2+7, (cols-2*5)/2+40);		
  }

  for (x=0;x<50;x++)
	mvaddch(rand()%rows, rand()%cols, 32);

  refresh();
  usleep(100000);
}

void scroller(int rows, int cols) {
  int i;

  clear();
  static int mesgpos, initdone=0;
  if (!initdone) {
	mesgpos=cols;	
	initdone++;
  }
  char mesg[]="Greetings to everyone at the 135 Party! We hope you're having a good time. Remember to drink. P.S. IMASKAAS!";
  printstr(mesg, 11, mesgpos);
  mesgpos--;

  for (i=0;i<50;i++)
	mvaddch(rand()%rows, rand()%cols, pii[pos++&255]+'0');

  for (i=0;i<7;i++)
    printchar(pii[pos++&255]+'0', 3, 5+i*15);

  for (i=0;i<7;i++)
    printchar(pii[pos++&255]+'0', 20, 5+i*15);

  refresh();
  usleep(100000);
}

void logo(int rows, int cols) {
  int x, y;
  int placex=(cols-LOGOX)/2, placey=(rows-LOGOY)/2;
  int efstartpos[LOGOY];

  static int initdone=0;
  if (!initdone) {
    for (x=0;x<LOGOY;x++)
      efstartpos[x] = rand()%rows;
    initdone++;
  }

  clear();

  for (y=0;y<rows;y++) for (x=0;x<cols;x++) {
	if (t<1470) {
	    mvaddch(y, x, pii[pos++&255]+'0');
    } else {
	  if (t%2)
	    mvaddch(y, x, pii[pos++&255]+'0');
      else {
		attron(A_BOLD);
	    mvaddch(y, x, 32);
		attroff(A_BOLD);
      }
    }
  }

  if (t >1420) {
    if (t%2==0)
      attron(A_BOLD);
  } else {
      attron(A_BOLD);	
  }
  for (y=0;y<LOGOY;y++) for (x=0;x<LOGOX;x++)
    if (pilogo[y*LOGOX+x]>32) mvaddch(placey+y, placex+x, pii[pos++&255]+'0');
  if (t >1400) {
    if (t%2==0)
      attroff(A_BOLD);
  } else {
    attroff(A_BOLD);	
  }

  int firstx;
  static int donecount=0, effectoffset=0;
  if (donecount >= LOGOY) effectoffset++;
  donecount=0;
  for (x=0;x<LOGOY;x++) {
    firstx=0;
    for(y=0;y<LOGOX;y++) {
      if (pilogo[x*LOGOX+y]<33) firstx++;
      else break;
    }

    if (efstartpos[x]>placey+x) efstartpos[x]--;
    else if (efstartpos[x]<placey+x) efstartpos[x]++;
    else donecount++;

    mvaddch(efstartpos[x], placex+firstx+effectoffset, (char)10);
  }

  mvaddch(rand()%rows, rand()%cols, 32);	

  refresh();
  usleep(100000);
}

int main() {
 int row,col;				/* to store the number of rows and *
					 * the number of colums of the screen */
 initscr();				/* start the curses mode */
 getmaxyx(stdscr,row,col);		/* get the number of rows and columns */

  if (precalc()) return 1;

 while (time<end) {
   if (time==0) intro(row, col);
   else if (time==1) onnee(row, col, 0);
   else if (time==2) naali(row, col);
   else if (time==3) biini(row, col);
   else if (time==4) t101(row, col);
   else if (time==5) duncan(row, col);
   else if (time==6) scroller(row, col); 
   else if (time==7) logo(row, col);
   t++;
   if (t==170) time++;
   if (t==320) time++;
   if (t==420) time++;
   if (t==520) time++;
   if (t==620) time++;
   if (t==720) time++;
   if (t==1350) time++;
   if (t==1800) time++;
 }

// getch();
 endwin();

 return 0;
}

